House Prices
House Prices
1 Objetivos
- Número de variáveis: 81
- Tipo de variáveis
- Inteiras ou discretas:
- Numéricas ou double
- Categóricas
- Qualitativas
- Qualidade dos dados
- Quantidade de NA’s por variável
- Criação de novas variáveis, se precisar
- Transformação das variáveis, se precisar
2 Conjunto de Dados de Treino
# Read table
df.train <- data.table::fread('../dados/train.csv',
sep=",",
showProgress = FALSE) %>%
data.frame(stringsAsFactors = F)
df.train3 Há quantos tipo de dados ?
lapply(df.train,class) %>%
unlist %>% as.character() %>% table## .
## character integer
## 43 38
4 Dados do tipo inteiro
df.int <- df.train[,unlist(lapply(df.train,is.integer))]
df.int4.1 Resumo dos dados
skim_to_wide(df.int)veja que há valores nulos presente na amostra, minha estratégia será remover variáveis que possuam muitos valores nulos e imputar dados para as variáveis com poucos valores nulos.
Primeiramente farei uma pré-seleção dos dados afim de saber se os dados que possuem valores nulos tem importância em relação a variável SalePrice.
5 O Algoritmo De Boruta
- Tenta selecionar as variáveis importantes do conjunto de dados que discriminam a variável resposta.
- Então ele treina um classificador no conjunto de dados.
- Faz um rank da importância da variável com base em um score.
set.seed(2510)
boruta.int <- Boruta(SalePrice ~ ., data=na.omit(df.int[,-1]), doTrace=2) # perform Boruta searchcols.int <- names(boruta.int$finalDecision[boruta.int$finalDecision %in% c("Confirmed", "Tentative")]) # collect5.1 Plot da importância da variável
plot(boruta.int, cex.axis=.7, las=2, xlab="", main="Variable Importance")Selecionando as variáveis inteiras
df.int <- df.int[,c('Id',"SalePrice",cols.int)]6 Qualidade dos dados
6.1 Tipo inteiro: % de valores nulos
apply(is.na(df.int),2,
function(x) round(100*sum(as.numeric(x))/length(x),2)) %>%
sort(decreasing = T)## LotFrontage GarageYrBlt MasVnrArea Id SalePrice
## 17.74 5.55 0.55 0.00 0.00
## MSSubClass LotArea OverallQual OverallCond YearBuilt
## 0.00 0.00 0.00 0.00 0.00
## YearRemodAdd BsmtFinSF1 BsmtUnfSF TotalBsmtSF X1stFlrSF
## 0.00 0.00 0.00 0.00 0.00
## X2ndFlrSF GrLivArea BsmtFullBath FullBath HalfBath
## 0.00 0.00 0.00 0.00 0.00
## BedroomAbvGr KitchenAbvGr TotRmsAbvGrd Fireplaces GarageCars
## 0.00 0.00 0.00 0.00 0.00
## GarageArea WoodDeckSF OpenPorchSF EnclosedPorch ScreenPorch
## 0.00 0.00 0.00 0.00 0.00
De forma geral não há muitos valores nulos no conjunto de variáveis inteiras, porém a variável LotFrontage apresenta cerca de 17.74 % de valores nulos ausentes e como há uma série de outras variáveis mais importantes que esta, decido por remove-la.
Removendo a variável LotFrontage
df.int <- df.int %>% select(-LotFrontage)6.2 Imputando dados com knn
Criando um modelo com o knn para imputar dados.
preProcess_missingdata_model <- preProcess(df.int[,-c(1,2)], method='knnImpute')
preProcess_missingdata_model## Created from 1371 samples and 27 variables
##
## Pre-processing:
## - centered (27)
## - ignored (0)
## - 5 nearest neighbor imputation (27)
## - scaled (27)
Vamos agora usar esse modelo para prever os valores ausentes df.int
df.int1 <- predict(preProcess_missingdata_model, newdata = df.int[,-c(1,2)] )
anyNA(df.int1)## [1] FALSE
Todos os valores ausentes foram imputados com sucesso, agora vamos juntar as colunas Id e SalesPrice com df.int1
df.int <- cbind(df.int[,c(1,2)],df.int1)Convertento dados tipo string para tipo categórico
df.fac <- df.train[,unlist(lapply(df.train,is.character))] %>%
apply(2,as.factor) %>%
data.frame()6.3 Tipo Categorical: % de valores nulos
apply(is.na(df.fac),2,function(x) round(100*sum(as.numeric(x))/length(x),2)) %>%
sort(decreasing = T)## PoolQC MiscFeature Alley Fence FireplaceQu
## 99.52 96.30 93.77 80.75 47.26
## GarageType GarageFinish GarageQual GarageCond BsmtExposure
## 5.55 5.55 5.55 5.55 2.60
## BsmtFinType2 BsmtQual BsmtCond BsmtFinType1 MasVnrType
## 2.60 2.53 2.53 2.53 0.55
## Electrical MSZoning Street LotShape LandContour
## 0.07 0.00 0.00 0.00 0.00
## Utilities LotConfig LandSlope Neighborhood Condition1
## 0.00 0.00 0.00 0.00 0.00
## Condition2 BldgType HouseStyle RoofStyle RoofMatl
## 0.00 0.00 0.00 0.00 0.00
## Exterior1st Exterior2nd ExterQual ExterCond Foundation
## 0.00 0.00 0.00 0.00 0.00
## Heating HeatingQC CentralAir KitchenQual Functional
## 0.00 0.00 0.00 0.00 0.00
## PavedDrive SaleType SaleCondition
## 0.00 0.00 0.00
Veja que as variáveis PoolQC, MiscFeature, Alley, Fence e FireplaceQu não nos deixam outra alternativa senão a remoção delas do conjunto de dados, pois neste caso, a imputação de dados seria um grande problema na propagação do erro considerando as incertezas associadas aos métodos de imputação.
6.4 Selecão de Variável Tipo String:
- PoolQC
- MiscFeature
- Alley
- Fence
- FireplaceQu
df.fac <- df.fac %>%
select(-PoolQC,-MiscFeature,
-Alley,-Fence,-FireplaceQu)
df.fac6.5 Pré-Seleção das Variáveis Categóricas
Novamente utilizarei o boruta para realizar uma pré-seleção das variáveis
set.seed(2510)
boruta_fac <- Boruta(SalePrice ~ ., data=na.omit(data.frame(SalePrice = df.int[,'SalePrice'],df.fac)), doTrace=2)
# perform Boruta searchatribuindo a cols.fac o nome das variáveis selecionadas.
cols.fac <- names(boruta_fac$finalDecision[boruta_fac$finalDecision %in% c("Confirmed", "Tentative")]) 6.6 Plot da importância da variável
plot(boruta_fac, cex.axis=.7, las=2, xlab="", main="Variable Importance")7 Variáveis selecionadas df.fac
df.fac <- df.fac[,cols.fac]apply(is.na(df.fac),2,function(x) round(100*sum(as.numeric(x))/length(x),2)) %>%
sort(decreasing = T)## GarageType GarageFinish GarageCond BsmtExposure BsmtQual
## 5.55 5.55 5.55 2.60 2.53
## BsmtCond BsmtFinType1 MasVnrType Electrical MSZoning
## 2.53 2.53 0.55 0.07 0.00
## LotShape LandContour LandSlope Neighborhood Condition1
## 0.00 0.00 0.00 0.00 0.00
## BldgType HouseStyle RoofStyle RoofMatl Exterior1st
## 0.00 0.00 0.00 0.00 0.00
## Exterior2nd ExterQual ExterCond Foundation HeatingQC
## 0.00 0.00 0.00 0.00 0.00
## CentralAir KitchenQual Functional PavedDrive SaleCondition
## 0.00 0.00 0.00 0.00 0.00
Como ainda estamos com valores nulos recorremos ao caret para imputar essas categorias.
Para construir um modelo que impute nas variáveis categóricas suas categorias faltantes vamos retirar todas as variáveis que possuem alguma porcentagem de valores nulos e deixar no data frame somente uma delas em cada modelo.
7.1 Criando os data frames
df.GarageType <- df.fac %>%
select(-GarageFinish,-GarageCond,
-BsmtExposure,-BsmtQual,
-BsmtCond,-BsmtFinType1,
-MasVnrType,-Electrical)df.GarageFinish <- df.fac %>%
select(-GarageType,-GarageCond,
-BsmtExposure,-BsmtQual,
-BsmtCond,-BsmtFinType1,
-MasVnrType,-Electrical)df.GarageCond <- df.fac %>%
select(-GarageType,-GarageFinish,
-BsmtExposure,-BsmtQual,
-BsmtCond,-BsmtFinType1,
-MasVnrType,-Electrical)df.BsmtExposure <- df.fac %>%
select(-GarageType,-GarageFinish,
-GarageCond,-BsmtQual,
-BsmtCond,-BsmtFinType1,
-MasVnrType,-Electrical)df.BsmtQual <- df.fac %>%
select(-GarageType,-GarageFinish,
-GarageCond,-BsmtExposure,
-BsmtCond,-BsmtFinType1,
-MasVnrType,-Electrical)df.BsmtCond <- df.fac %>%
select(-GarageType,-GarageFinish,
-GarageCond,-BsmtExposure,
-BsmtQual,-BsmtFinType1,
-MasVnrType,-Electrical)df.BsmtFinType1 <- df.fac %>%
select(-GarageType,-GarageFinish,
-GarageCond,-BsmtExposure,
-BsmtQual,-BsmtCond,
-MasVnrType,-Electrical)df.MasVnrType <- df.fac %>%
select(-GarageType,-GarageFinish,
-GarageCond,-BsmtExposure,
-BsmtQual,-BsmtCond,
-BsmtFinType1,-Electrical)df.Electrical <- df.fac %>%
select(-GarageType,-GarageFinish,
-GarageCond,-BsmtExposure,
-BsmtQual,-BsmtCond,
-BsmtFinType1,-MasVnrType)criando um vetor com o nome das variáveis e uma lista com os data-frames criados.
vars <- c('GarageType','GarageFinish',
'GarageCond','BsmtExposure',
'BsmtQual','BsmtCond',
'BsmtFinType1','MasVnrType',
'Electrical')
list.df <- list(df.GarageType,df.GarageFinish,
df.GarageCond,df.BsmtExposure,
df.BsmtQual,df.BsmtCond,
df.BsmtFinType1,df.MasVnrType,
df.Electrical)A função abaixo automatiza o processo de impute das categoricas nos valores nulos de cada variável.
f.pred <- function(fac,df.var,rf.model,var){
new.df <- df.var[is.na(df.var[,var]),!(names(df.var) %in% var)]
pred_rf <- predict(rf.model, newdata = new.df)
fac[is.na(fac[,var]),var] <- pred_rf
return(fac)
}7.2 Usando a Caret e RandomForest
Utilizarei o random forest como classificador para imputar as categorias faltantes.
set.seed(12345)
fitControl <- trainControl(method="cv",
number=3,
savePredictions = 'final',
classProbs= F,
summaryFunction = multiClassSummary)Construindos os modelos para imputar os valores nulos, para cada variável terei um modelo.
set.seed(12345)
# Crio uma lista para armazenar os modelos
rf.list <- list()
for(j in 1:length(vars)){
# atribuo em df um df."variavel" sem os valor nulos
df <- list.df[[j]] %>% na.omit()
# treino esse df. no random-forest
rf.list[[j]] <- train(eval(parse(text = paste(vars[j],'~.'))),
data = df,
tuneLength=5,
trControl = fitControl,method='rf')
# imputo as categorias faltantes no valores nulos das variáveis
df.fac <- f.pred(df.fac,list.df[[j]],rf.list[[j]],vars[j])
cat(j,' - ')
}## 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -
Será há algum valor nulos ?
anyNA(df.fac)## [1] FALSE
Imputação de dados realizada com sucesso !
8 Juntandos os data frames
Jutando os dados tipo inteiros e string.
df.train <- bind_cols(df.int,df.fac)Agora nosso df.train encontra-se limpo e pronto para ser explorado.
9 Exportando os dados
write.csv(df.train,'../outputs/df.train.csv')
saveRDS(cols.int,'../outputs/cols.int.rds')
saveRDS(cols.fac,'../outputs/cols.fac.rds')